package com.nulstudio.sppm.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.nulstudio.sppm.config.NulSecurityConfig;
import com.nulstudio.sppm.domain.dto.UserManagementDto;
import com.nulstudio.sppm.domain.vo.UserManagementVo;
import com.nulstudio.sppm.entity.NulRole;
import com.nulstudio.sppm.entity.NulUserDetail;
import com.nulstudio.sppm.exception.NulException;
import com.nulstudio.sppm.exception.NulExceptionConstants;
import com.nulstudio.sppm.mapper.AccountMapper;
import com.nulstudio.sppm.mapper.AuthorityMapper;
import com.nulstudio.sppm.mapper.UserManagementMapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.NonNull;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public final class UserManagementService {

    private final Logger log = LoggerFactory.getLogger(UserManagementService.class);

    @Value("${config.default-password}")
    private String DEFAULT_PASSWORD;

    @Resource
    @NonNull
    private AccountMapper accountMapper;

    @Resource
    @NonNull
    private AuthorityMapper authorityMapper;

    @Resource
    @NonNull
    private UserManagementMapper userManagementMapper;

    @NonNull
    public PageInfo<UserManagementVo> fetchAll(@NonNull String name, int page, int pageSize) {
        final PageInfo<UserManagementVo> result;
        try (
                final Page<UserManagementVo> ignored = PageHelper.startPage(page, pageSize)
        ) {
            final List<UserManagementVo> userManagementList = userManagementMapper.fetchAll(name);
            result = new PageInfo<>(userManagementList);
        } catch (Exception e) {
            log.error("Error", e);
            throw new NulException(NulExceptionConstants.INTERNAL_SERVER_ERROR, e.getMessage());
        }
        return result;
    }

    public void createUser(@NonNull UserManagementDto userManagementDto) {
        if (accountMapper.checkUserExistence(userManagementDto.userName())) {
            throw new NulException(NulExceptionConstants.USER_ALREADY_EXIST);
        }
        final String encryptedPassword = new BCryptPasswordEncoder().encode(DEFAULT_PASSWORD);
        final NulRole role = authorityMapper.getRoleByName(userManagementDto.role());
        NulRole.assertValidity(role);
        final int roleId = role.getId();
        final NulUserDetail userDetail = new NulUserDetail(userManagementDto.gender(), userManagementDto.userName(),
                userManagementDto.name(), encryptedPassword, roleId);
        NulUserDetail.assertValidity(userDetail);
        if (accountMapper.insertUser(userDetail) == 0) {
            throw new NulException(NulExceptionConstants.INTERNAL_SERVER_ERROR);
        }
    }

    public void updateUser(int uid, @NonNull UserManagementDto userManagementDto) {
        final NulUserDetail user = accountMapper.getUserById(uid);
        if (user == null) {
            throw new NulException(NulExceptionConstants.USER_NOT_EXIST);
        }
        if (!user.getUserName().equals(userManagementDto.userName()) &&
                accountMapper.checkUserExistence(userManagementDto.userName())) {
            throw new NulException(NulExceptionConstants.USER_ALREADY_EXIST);
        }
        final NulRole role = authorityMapper.getRoleByName(userManagementDto.role());
        if (role == null) {
            throw new NulException(NulExceptionConstants.ROLE_NOT_EXIST);
        }
        final NulUserDetail userDetail = new NulUserDetail(uid, userManagementDto.userName(), userManagementDto.name(),
                userManagementDto.gender(), role.getId());
        NulUserDetail.assertValidity(userDetail);
        final int result = userManagementMapper.update(userDetail);
        if (result <= 0) {
            throw new NulException(NulExceptionConstants.USER_NOT_EXIST);
        }
    }

    public void deleteUser(int uid) {
        final NulUserDetail userDetail = NulSecurityConfig.getContextUserDetail();
        final int currentUid = userDetail.getUid();
        if (uid == currentUid) {
            throw new NulException(NulExceptionConstants.DELETING_SELF);
        }
        final int result = userManagementMapper.delete(uid);
        if (result <= 0) {
            throw new NulException(NulExceptionConstants.USER_NOT_EXIST);
        }
    }
}
